Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / http / routes / reticulum_instance.py

Displaying Raw • Download


meshchatx/src/backend/http/routes/reticulum_instance.py 4bd787ccd70a459a02eececca3f942f0e64ec4ce (4bd787cc) Text, 30.71 KB

T8b949e# SPDX-License-Identifier: 0BSD
T8b949e"""HTTP routes: reticulum_instance."""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations


Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787httpT7ee787.T7ee787meshchat_names Tff7b72import Tb4b4b4( T8b949e# noqa: F401
Te6edf3GeoValidationErrorTb4b4b4,
Te6edf3OutboundHttpBlockedErrorTb4b4b4,
Te6edf3OverlayExportErrorTb4b4b4,
Te6edf3OverlaySourceParseErrorTb4b4b4,
Te6edf3PluginSecurityErrorTb4b4b4,
Te6edf3AsyncUtilsTb4b4b4,
Te6edf3InterfaceConfigParserTb4b4b4,
Te6edf3InterfaceDiscoveryTb4b4b4,
Te6edf3InterfaceEditorTb4b4b4,
Te6edf3LOGIN_PATHTb4b4b4,
Te6edf3LXMFTb4b4b4,
Te6edf3LxmfAudioFieldTb4b4b4,
Te6edf3LxmfFileAttachmentTb4b4b4,
Te6edf3LxmfFileAttachmentsFieldTb4b4b4,
Te6edf3LxmfImageFieldTb4b4b4,
Te6edf3MAX_EXPORT_TILESTb4b4b4,
Te6edf3MarkdownRendererTb4b4b4,
Te6edf3NomadnetFileDownloaderTb4b4b4,
Te6edf3NomadnetPageDownloaderTb4b4b4,
Te6edf3RNProbeHandlerTb4b4b4,
Te6edf3RNSTb4b4b4,
Te6edf3ReticulumMeshChatTb4b4b4,
Te6edf3SETUP_PATHTb4b4b4,
Te6edf3TRANSPARENT_TILETb4b4b4,
Te6edf3TelemeterTb4b4b4,
Te6edf3UTCTb4b4b4,
Te6edf3WSMsgTypeTb4b4b4,
Te6edf3_is_chaquopy_androidTb4b4b4,
Te6edf3_is_loopback_bind_hostTb4b4b4,
Te6edf3_request_client_ipTb4b4b4,
Te6edf3aiohttpTb4b4b4,
Te6edf3app_versionTb4b4b4,
Te6edf3assert_migration_context_pathsTb4b4b4,
Te6edf3asyncioTb4b4b4,
Te6edf3base64Tb4b4b4,
Te6edf3bcryptTb4b4b4,
Te6edf3binasciiTb4b4b4,
Te6edf3build_blocklist_export_documentTb4b4b4,
Te6edf3build_export_documentTb4b4b4,
Te6edf3build_messages_export_bundleTb4b4b4,
Te6edf3cache_statsTb4b4b4,
Te6edf3cancel_inbound_deliveriesTb4b4b4,
Te6edf3castTb4b4b4,
Te6edf3compute_lxmf_conversation_unread_from_latest_rowTb4b4b4,
Te6edf3configparserTb4b4b4,
Te6edf3contextlibTb4b4b4,
Te6edf3convert_db_favourite_to_dictTb4b4b4,
Te6edf3convert_db_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_nomadnet_field_data_to_mapTb4b4b4,
Te6edf3convert_nomadnet_string_data_to_mapTb4b4b4,
Te6edf3convert_propagation_node_state_to_stringTb4b4b4,
Te6edf3copyTb4b4b4,
Te6edf3datetimeTb4b4b4,
Te6edf3describe_port_conflictTb4b4b4,
Te6edf3detect_image_format_from_magicTb4b4b4,
Te6edf3ensure_outbound_http_allowedTb4b4b4,
Te6edf3ensure_session_csrf_tokenTb4b4b4,
Te6edf3filter_announced_dicts_by_search_queryTb4b4b4,
Te6edf3fresh_storage_at_targetTb4b4b4,
Te6edf3get_cached_active_linkTb4b4b4,
Te6edf3get_file_pathTb4b4b4,
Te6edf3get_sessionTb4b4b4,
Te6edf3get_trusted_proxy_cidrsTb4b4b4,
Te6edf3gif_utilsTb4b4b4,
Te6edf3i2p_supportTb4b4b4,
Te6edf3import_messages_export_bundleTb4b4b4,
Te6edf3ioTb4b4b4,
Te6edf3is_mbtiles_filenameTb4b4b4,
Te6edf3is_path_within_dirTb4b4b4,
Te6edf3is_port_in_useTb4b4b4,
Te6edf3is_user_facing_lxmf_payloadTb4b4b4,
Te6edf3jsonTb4b4b4,
Te6edf3list_host_network_interfacesTb4b4b4,
Te6edf3list_inbound_deliveriesTb4b4b4,
Te6edf3list_portsTb4b4b4,
Te6edf3load_app_security_settingsTb4b4b4,
Te6edf3loggerTb4b4b4,
Te6edf3loggingTb4b4b4,
Te6edf3lxmf_sidebar_preview_for_conversation_latest_rowTb4b4b4,
Te6edf3memory_log_handlerTb4b4b4,
Te6edf3message_fields_have_attachmentsTb4b4b4,
Te6edf3migrate_legacy_to_targetTb4b4b4,
Te6edf3mime_for_image_typeTb4b4b4,
Te6edf3normalize_identity_storage_hashTb4b4b4,
Te6edf3normalize_lxmf_sieve_filtersTb4b4b4,
Te6edf3normalize_message_blocklistTb4b4b4,
Te6edf3osTb4b4b4,
Te6edf3parse_bool_query_paramTb4b4b4,
Te6edf3parse_import_documentTb4b4b4,
Te6edf3parse_lxmf_display_nameTb4b4b4,
Te6edf3parse_lxmf_propagation_node_app_dataTb4b4b4,
Te6edf3parse_lxmf_sieve_filters_jsonTb4b4b4,
Te6edf3parse_lxmf_stamp_costTb4b4b4,
Te6edf3parse_message_blocklist_jsonTb4b4b4,
Te6edf3parse_nomadnetwork_node_display_nameTb4b4b4,
Te6edf3platformTb4b4b4,
Te6edf3privacy_mode_enabledTb4b4b4,
Te6edf3psutilTb4b4b4,
Te6edf3purge_messages_before_cutoffTb4b4b4,
Te6edf3reTb4b4b4,
Te6edf3resolve_message_age_cutoffTb4b4b4,
Te6edf3reticulum_pathfindingTb4b4b4,
Te6edf3rotate_session_csrf_tokenTb4b4b4,
Te6edf3rrc_protocolTb4b4b4,
Te6edf3safe_path_under_dirTb4b4b4,
Te6edf3sanitize_sticker_emojiTb4b4b4,
Te6edf3sanitize_sticker_nameTb4b4b4,
Te6edf3sanitize_websocket_config_updateTb4b4b4,
Te6edf3save_app_security_settingsTb4b4b4,
Te6edf3secretsTb4b4b4,
Te6edf3shutilTb4b4b4,
Te6edf3sqlite3Tb4b4b4,
Te6edf3sticker_pack_utilsTb4b4b4,
Te6edf3sysTb4b4b4,
Te6edf3tempfileTb4b4b4,
Te6edf3threadingTb4b4b4,
Te6edf3timeTb4b4b4,
Te6edf3tracebackTb4b4b4,
Te6edf3user_agent_hashTb4b4b4,
Te6edf3validate_export_documentTb4b4b4,
Te6edf3webTb4b4b4,
Te6edf3websocket_type_requires_authTb4b4b4,
Te6edf3zipfileTb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8ffregister_reticulum_instance_routesTb4b4b4(Te6edf3routesTb4b4b4, Te6edf3appTb4b4b4)Tb4b4b4:

T8b949e# get or update reticulum discovery configuration
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/discoveryTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_discovery_getTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3reticulum_config Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_reticulum_sectionTb4b4b4(Tb4b4b4)
Te6edf3discovery_config Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_sourcesTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_sourcesTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffrequired_discovery_valueTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffrequired_discovery_valueTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff"Tb4b4b4,
Te6edf3ReticulumMeshChatTff7b72.Td2a8ffDEFAULT_AUTOCONNECT_DISCOVERED_INTERFACESTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffdefault_gravityTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdefault_gravityTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_interface_gravityTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_interface_gravityTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffdefault_bootstrap_onlyTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(
Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfigTff7b72.Td2a8ffdefault_bootstrap_onlyTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3appTff7b72.Td2a8ffcurrent_context Tff7b72and Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfig
Tff7b72else Tff7b72FalseTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffnetwork_identityTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnetwork_identityTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4}

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffdiscoveryTa5d6ff"Tb4b4b4: Te6edf3discovery_configTb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpatchTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/discoveryTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_discovery_patchTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid request bodyTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3reticulum_config Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_reticulum_sectionTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8ffupdate_config_valueTb4b4b4(Te6edf3keyTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3key Tff7b72not Tff7b72in Te6edf3dataTb4b4b4:
Tff7b72return
Te6edf3value Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Te6edf3keyTb4b4b4)
T8b949e# Treat 0 for autoconnect_discovered_interfaces the same as unset,
T8b949e# since Reticulum interprets 0 as False, causing bootstrap_only
T8b949e# interfaces to flap (0 >= 0 evaluates to True).
Tff7b72if Tb4b4b4(
Te6edf3value Tff7b72is Tff7b72None
Tff7b72or Te6edf3value Tff7b72== Ta5d6ff"Ta5d6ff"
Tff7b72or Tb4b4b4(Te6edf3key Tff7b72== Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff" Tff7b72and Te6edf3value Tff7b72== T79c0ff0Tb4b4b4)
Tb4b4b4)Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Te6edf3keyTb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72if Te6edf3key Tff7b72in Tb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3sanitized Tff7b72= Te6edf3ReticulumMeshChatTff7b72.Td2a8ffsanitize_discovery_patternsTb4b4b4(Te6edf3valueTb4b4b4)
Tff7b72if Te6edf3sanitizedTb4b4b4:
Te6edf3reticulum_configTb4b4b4[Te6edf3keyTb4b4b4] Tff7b72= Ta5d6ff"Ta5d6ff,Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3sanitizedTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Te6edf3keyTb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72return
Te6edf3reticulum_configTb4b4b4[Te6edf3keyTb4b4b4] Tff7b72= Te6edf3value

Tff7b72for Te6edf3key Tff7b72in Tb4b4b4(
Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_sourcesTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffrequired_discovery_valueTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnetwork_identityTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3update_config_valueTb4b4b4(Te6edf3keyTb4b4b4)

Tff7b72if Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff" Tff7b72in Te6edf3dataTb4b4b4:
Te6edf3mode_raw Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3mode_raw Tff7b72is Tff7b72None Tff7b72or Te6edf3mode_raw Tff7b72== Ta5d6ff"Ta5d6ff"Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3mode Tff7b72= Te6edf3InterfaceEditorTff7b72.Td2a8ffnormalize_interface_modeTb4b4b4(Te6edf3mode_rawTb4b4b4)
Tff7b72if Te6edf3mode Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_interface_mode must be one of: Ta5d6ff"
Ta5d6ff"Ta5d6fffull, gateway, access_point, pointtopoint, Ta5d6ff"
Ta5d6ff"Ta5d6ffroaming, boundary, internalTa5d6ff"
Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff422Tb4b4b4,
Tb4b4b4)
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3mode

Tff7b72if Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff" Tff7b72in Te6edf3dataTb4b4b4:
Te6edf3yn Tff7b72= Te6edf3InterfaceEditorTff7b72.Td2a8ffrequest_yes_noTb4b4b4(
Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3yn Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3raw Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3raw Tff7b72is Tff7b72None Tff7b72or Te6edf3raw Tff7b72== Ta5d6ff"Ta5d6ff"Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72elseTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_announces_to_internal must be Ta5d6ff"
Ta5d6ff"Ta5d6ffa boolean or yes/no valueTa5d6ff"
Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff422Tb4b4b4,
Tb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3yn

Tff7b72for Te6edf3gravity_key Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6ffdefault_gravityTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffautoconnect_interface_gravityTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3gravity_key Tff7b72not Tff7b72in Te6edf3dataTb4b4b4:
Tff7b72continue
Te6edf3value Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Te6edf3gravity_keyTb4b4b4)
Tff7b72if Te6edf3value Tff7b72is Tff7b72None Tff7b72or Te6edf3value Tff7b72== Ta5d6ff"Ta5d6ff"Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Te6edf3gravity_keyTb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72continue
Tff7b72tryTb4b4b4:
Te6edf3gravity Tff7b72= Tffa657intTb4b4b4(Te6edf3valueTb4b4b4)
Tff7b72except Tb4b4b4(Tf85149TypeErrorTb4b4b4, Tf85149ValueErrorTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Tffd700{Te6edf3gravity_keyTffd700}Ta5d6ff must be an integerTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff422Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3gravity Tff7b72< Tff7b72-T79c0ff10_000 Tff7b72or Te6edf3gravity Tff7b72> T79c0ff10_000Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Tffd700{Te6edf3gravity_keyTffd700}Ta5d6ff must be between -10000 and 10000Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff422Tb4b4b4,
Tb4b4b4)
Te6edf3reticulum_configTb4b4b4[Te6edf3gravity_keyTb4b4b4] Tff7b72= Te6edf3gravity

T8b949e# When discover_interfaces is off, also disable autoconnect so RNS
T8b949e# does not connect to any discovered interfaces.
Tff7b72if Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff" Tff7b72in Te6edf3dataTb4b4b4:
Te6edf3disc_val Tff7b72= Te6edf3dataTb4b4b4[Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff"Tb4b4b4]
Tff7b72if Te6edf3disc_val Tff7b72is Tff7b72False Tff7b72or Tffa657strTb4b4b4(Te6edf3disc_valTb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6fffalseTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffnoTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff0Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)

T8b949e# default_bootstrap_only is a MeshChatX-only setting, so do NOT write it
T8b949e# to Reticulum config so discovered/auto-connected interfaces are
T8b949e# never affected. Clean up any stale value in Reticulum config.
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffdefault_bootstrap_onlyTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72if Tb4b4b4(
Te6edf3appTff7b72.Td2a8ffcurrent_context
Tff7b72and Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfig
Tff7b72and Ta5d6ff"Ta5d6ffdefault_bootstrap_onlyTa5d6ff" Tff7b72in Te6edf3data
Tb4b4b4)Tb4b4b4:
Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfigTff7b72.Td2a8ffdefault_bootstrap_onlyTff7b72.Td2a8ffsetTb4b4b4(
Tffa657boolTb4b4b4(Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdefault_bootstrap_onlyTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ff_write_reticulum_configTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFailed to write Reticulum configTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72tryTb4b4b4:
Te6edf3reloaded Tff7b72= Tff7b72await Te6edf3appTff7b72.Td2a8ffreload_reticulumTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3reloaded Tff7b72is Tff7b72FalseTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffDiscovery settings saved but RNS reload failedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffreloadedTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggerTff7b72.Td2a8ffdebugTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to reload RNS after discovery config update: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffDiscovery settings saved but RNS reload failed: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffreloadedTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Te6edf3discovery_config Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdiscover_interfacesTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_sourcesTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_sourcesTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffrequired_discovery_valueTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffrequired_discovery_valueTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_discovered_interfacesTa5d6ff"Tb4b4b4,
Te6edf3ReticulumMeshChatTff7b72.Td2a8ffDEFAULT_AUTOCONNECT_DISCOVERED_INTERFACESTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffdefault_gravityTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdefault_gravityTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_interface_modeTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_interface_gravityTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_interface_gravityTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffautoconnect_announces_to_internalTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffdefault_bootstrap_onlyTa5d6ff"Tb4b4b4: Tffa657boolTb4b4b4(
Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfigTff7b72.Td2a8ffdefault_bootstrap_onlyTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3appTff7b72.Td2a8ffcurrent_context Tff7b72and Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfig
Tff7b72else Tff7b72FalseTb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffnetwork_identityTa5d6ff"Tb4b4b4: Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnetwork_identityTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffreloadedTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffdiscoveryTa5d6ff"Tb4b4b4: Te6edf3discovery_configTb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/discovered-interfacesTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_discovered_interfacesTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3discovery Tff7b72= Te6edf3InterfaceDiscoveryTb4b4b4(Te6edf3discover_interfacesTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3interfaces Tff7b72= Te6edf3discoveryTff7b72.Td2a8fflist_discovered_interfacesTb4b4b4(Tb4b4b4)
Te6edf3reticulum_config Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_reticulum_sectionTb4b4b4(Tb4b4b4)
Te6edf3whitelist_patterns Tff7b72= Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_whitelistTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3blacklist_patterns Tff7b72= Te6edf3reticulum_configTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6ffinterface_discovery_blacklistTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3max_disc Tff7b72= T79c0ff500
Tff7b72if Te6edf3appTff7b72.Td2a8ffcurrent_context Tff7b72and Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfigTb4b4b4:
Te6edf3mv Tff7b72= Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffconfigTff7b72.Td2a8ffdiscovered_interfaces_max_returnTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3mv Tff7b72is Tff7b72not Tff7b72None Tff7b72and Te6edf3mv Tff7b72> T79c0ff0Tb4b4b4:
Te6edf3max_disc Tff7b72= Tffa657minTb4b4b4(Tffa657intTb4b4b4(Te6edf3mvTb4b4b4)Tb4b4b4, T79c0ff50_000Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3interfacesTb4b4b4) Tff7b72> Te6edf3max_discTb4b4b4:
Te6edf3interfaces Tff7b72= Te6edf3interfacesTb4b4b4[Tb4b4b4:Te6edf3max_discTb4b4b4]
Te6edf3active Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3stats Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_interface_stats_payloadTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4)
Tff7b72for Te6edf3s Tff7b72in Te6edf3statsTb4b4b4:
Te6edf3name Tff7b72= Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"
Te6edf3parsed_host Tff7b72= Tff7b72None
Te6edf3parsed_port Tff7b72= Tff7b72None
Tff7b72if Ta5d6ff"Ta5d6ff/Ta5d6ff" Tff7b72in Te6edf3nameTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3host_port Tff7b72= Te6edf3nameTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]Tff7b72.Td2a8ffstripTb4b4b4(Ta5d6ff"Ta5d6ff[]Ta5d6ff"Tb4b4b4)
Tff7b72if Ta5d6ff"Ta5d6ff:Ta5d6ff" Tff7b72in Te6edf3host_portTb4b4b4:
Te6edf3parsed_hostTb4b4b4, Te6edf3parsed_port Tff7b72= Te6edf3host_portTff7b72.Td2a8ffrsplitTb4b4b4(
Ta5d6ff"Ta5d6ff:Ta5d6ff"Tb4b4b4,
T79c0ff1Tb4b4b4,
Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3parsed_port Tff7b72= Tffa657intTb4b4b4(Te6edf3parsed_portTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Te6edf3parsed_port Tff7b72= Tff7b72None
Tff7b72elseTb4b4b4:
Te6edf3parsed_host Tff7b72= Te6edf3host_port
Tff7b72except Tf85149ExceptionTb4b4b4:
Te6edf3parsed_host Tff7b72= Tff7b72None
Te6edf3parsed_port Tff7b72= Tff7b72None

Te6edf3host Tff7b72= Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftarget_hostTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremoteTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3parsed_host
Te6edf3port Tff7b72= Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftarget_portTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflisten_portTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3parsed_port
Te6edf3transport_id Tff7b72= Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftransport_idTa5d6ff"Tb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3transport_idTb4b4b4, Tb4b4b4(Tffa657bytesTb4b4b4, Tffa657bytearrayTb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3transport_id Tff7b72= Te6edf3transport_idTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)

Te6edf3activeTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Te6edf3nameTb4b4b4,
Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fftarget_hostTa5d6ff"Tb4b4b4: Te6edf3hostTb4b4b4,
Ta5d6ff"Ta5d6fftarget_portTa5d6ff"Tb4b4b4: Te6edf3portTb4b4b4,
Ta5d6ff"Ta5d6fflisten_ipTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflisten_ipTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffconnectedTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffconnectedTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffonlineTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffonlineTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fftransport_idTa5d6ff"Tb4b4b4: Te6edf3transport_idTb4b4b4,
Ta5d6ff"Ta5d6ffnetwork_idTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnetwork_idTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffautoconnect_sourceTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffautoconnect_sourceTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fftxbTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftxbTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffrxbTa5d6ff"Tb4b4b4: Te6edf3sTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffrxbTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tff7b72if Tffa657lenTb4b4b4(Te6edf3activeTb4b4b4) Tff7b72> Te6edf3max_discTb4b4b4:
Te6edf3active Tff7b72= Te6edf3activeTb4b4b4[Tb4b4b4:Te6edf3max_discTb4b4b4]

Tff7b72def Td2a8ffto_jsonableTb4b4b4(Te6edf3objTb4b4b4)Tb4b4b4:
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3objTb4b4b4, Tffa657bytesTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3objTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3objTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4{Te6edf3kTb4b4b4: Te6edf3to_jsonableTb4b4b4(Te6edf3vTb4b4b4) Tff7b72for Te6edf3kTb4b4b4, Te6edf3v Tff7b72in Te6edf3objTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4}
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3objTb4b4b4, Tffa657listTb4b4b4)Tb4b4b4:
Tff7b72return Tb4b4b4[Te6edf3to_jsonableTb4b4b4(Te6edf3vTb4b4b4) Tff7b72for Te6edf3v Tff7b72in Te6edf3objTb4b4b4]
Tff7b72return Te6edf3obj

Te6edf3normalized_interfaces Tff7b72= Te6edf3ReticulumMeshChatTff7b72.Td2a8ffnormalize_discovered_ifac_fieldsTb4b4b4(
Te6edf3to_jsonableTb4b4b4(Te6edf3interfacesTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3whitelist_sanitized Tff7b72= Te6edf3ReticulumMeshChatTff7b72.Td2a8ffsanitize_discovery_patternsTb4b4b4(
Te6edf3whitelist_patternsTb4b4b4,
Tb4b4b4)
Te6edf3blacklist_sanitized Tff7b72= Te6edf3ReticulumMeshChatTff7b72.Td2a8ffsanitize_discovery_patternsTb4b4b4(
Te6edf3blacklist_patternsTb4b4b4,
Tb4b4b4)
Tff7b72for Te6edf3iface Tff7b72in Te6edf3normalized_interfacesTb4b4b4:
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3ifaceTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffis_allowedTa5d6ff"Tb4b4b4] Tff7b72= Tb4b4b4(
Te6edf3ReticulumMeshChatTff7b72.Td2a8ffmatches_discovery_patternTb4b4b4(
Te6edf3whitelist_sanitizedTb4b4b4,
Te6edf3ifaceTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3whitelist_patterns
Tff7b72else Tff7b72True
Tb4b4b4)
Te6edf3ifaceTb4b4b4[Ta5d6ff"Ta5d6ffis_blacklistedTa5d6ff"Tb4b4b4] Tff7b72= Tb4b4b4(
Te6edf3ReticulumMeshChatTff7b72.Td2a8ffmatches_discovery_patternTb4b4b4(
Te6edf3blacklist_sanitizedTb4b4b4,
Te6edf3ifaceTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3blacklist_patterns
Tff7b72else Tff7b72False
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4: Te6edf3normalized_interfacesTb4b4b4,
Ta5d6ff"Ta5d6ffactiveTa5d6ff"Tb4b4b4: Te6edf3to_jsonableTb4b4b4(Te6edf3activeTb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffFailed to load discovered interfaces: Tffd700{Te6edf3eTffd700!s}Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

T8b949e# enable transport mode

T8b949e# enable transport mode
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/enable-transportTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_enable_transportTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# enable transport mode
Te6edf3reticulum_config Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_reticulum_sectionTb4b4b4(Tb4b4b4)
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffenable_transportTa5d6ff"Tb4b4b4] Tff7b72= Tff7b72True
Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ff_write_reticulum_configTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFailed to write Reticulum configTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72await Te6edf3appTff7b72.Td2a8ffreload_reticulumTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTransport mode was enabled in config, but RNS reload failed.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTransport mode enabled and RNS restarted successfully.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

T8b949e# disable transport mode

T8b949e# disable transport mode
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/disable-transportTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_disable_transportTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# disable transport mode
Te6edf3reticulum_config Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_reticulum_sectionTb4b4b4(Tb4b4b4)
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffenable_transportTa5d6ff"Tb4b4b4] Tff7b72= Tff7b72False
Te6edf3i2p_supportTff7b72.Td2a8ffdisable_i2p_when_transport_offTb4b4b4(
Te6edf3appTff7b72.Td2a8ff_get_interfaces_sectionTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3reticulum_configTb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ff_write_reticulum_configTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFailed to write Reticulum configTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72await Te6edf3appTff7b72.Td2a8ffreload_reticulumTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTransport mode was disabled in config, but RNS reload failed.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffTransport mode disabled and RNS restarted successfully.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/instanceTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_instance_getTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e"""Shared-instance, RPC, and hop-obfuscation settings (Sideband parity)."""
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffinstanceTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ff_build_reticulum_instance_settingsTb4b4b4(Tb4b4b4)Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpatchTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/instanceTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_instance_patchTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e"""Update [reticulum] shared-instance / hop-obfuscation options and reload."""
Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid request bodyTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3dataTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid request bodyTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3reticulum_config Tff7b72= Te6edf3appTff7b72.Td2a8ff_get_reticulum_sectionTb4b4b4(Tb4b4b4)
Te6edf3changed Tff7b72= Tff7b72False

Te6edf3bool_keys Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffshare_instanceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflocal_hops_deltaTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffrespond_to_probesTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffenable_remote_managementTa5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72for Te6edf3key Tff7b72in Te6edf3bool_keysTb4b4b4:
Tff7b72if Te6edf3key Tff7b72not Tff7b72in Te6edf3dataTb4b4b4:
Tff7b72continue
Te6edf3reticulum_configTb4b4b4[Te6edf3keyTb4b4b4] Tff7b72= Te6edf3appTff7b72.Td2a8ff_format_rns_config_boolTb4b4b4(
Te6edf3appTff7b72.Td2a8ff_parse_rns_config_boolTb4b4b4(Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Te6edf3keyTb4b4b4)Tb4b4b4, Te6edf3defaultTff7b72=Tff7b72FalseTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3changed Tff7b72= Tff7b72True

Tff7b72if Ta5d6ff"Ta5d6ffinstance_nameTa5d6ff" Tff7b72in Te6edf3dataTb4b4b4:
Te6edf3name Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinstance_nameTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3name Tff7b72is Tff7b72None Tff7b72or Tffa657strTb4b4b4(Te6edf3nameTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ff"Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffinstance_nameTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3cleaned Tff7b72= Tffa657strTb4b4b4(Te6edf3nameTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3cleanedTb4b4b4) Tff7b72> T79c0ff64 Tff7b72or Tffa657anyTb4b4b4(Te6edf3cTff7b72.Td2a8ffisspaceTb4b4b4(Tb4b4b4) Tff7b72for Te6edf3c Tff7b72in Te6edf3cleanedTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffinstance_name must be 1-64 characters without whitespaceTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffinstance_nameTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3cleaned
Te6edf3changed Tff7b72= Tff7b72True

Tff7b72if Ta5d6ff"Ta5d6ffshared_instance_typeTa5d6ff" Tff7b72in Te6edf3dataTb4b4b4:
Te6edf3raw_type Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffshared_instance_typeTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3raw_type Tff7b72is Tff7b72None Tff7b72or Tffa657strTb4b4b4(Te6edf3raw_typeTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ff"Tb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffshared_instance_typeTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Tff7b72elseTb4b4b4:
Te6edf3cleaned_type Tff7b72= Tffa657strTb4b4b4(Te6edf3raw_typeTb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3cleaned_type Tff7b72not Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6fftcpTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffunixTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffshared_instance_type must be Ta5d6ff'Ta5d6fftcpTa5d6ff'Ta5d6ff or Ta5d6ff'Ta5d6ffunixTa5d6ff'Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffshared_instance_typeTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3cleaned_type
Te6edf3changed Tff7b72= Tff7b72True

Tff7b72if Ta5d6ff"Ta5d6ffremote_management_allowedTa5d6ff" Tff7b72in Te6edf3dataTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3allowed Tff7b72= Te6edf3appTff7b72.Td2a8ff_parse_rns_hash_listTb4b4b4(
Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffremote_management_allowedTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149ValueError Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff400Tb4b4b4)
Tff7b72if Te6edf3allowedTb4b4b4:
Te6edf3reticulum_configTb4b4b4[Ta5d6ff"Ta5d6ffremote_management_allowedTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3allowed
Tff7b72elseTb4b4b4:
Te6edf3reticulum_configTff7b72.Td2a8ffpopTb4b4b4(Ta5d6ff"Ta5d6ffremote_management_allowedTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Te6edf3changed Tff7b72= Tff7b72True

Tff7b72if Tff7b72not Te6edf3changedTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffinstanceTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ff_build_reticulum_instance_settingsTb4b4b4(Tb4b4b4)Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tff7b72if Tff7b72not Te6edf3appTff7b72.Td2a8ff_write_reticulum_configTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFailed to write Reticulum configTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72if Tff7b72not Tff7b72await Te6edf3appTff7b72.Td2a8ffreload_reticulumTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInstance settings were saved, but RNS reload failed.Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffinstanceTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ff_build_reticulum_instance_settingsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffReticulum instance settings updated and RNS restarted.Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffinstanceTa5d6ff"Tb4b4b4: Te6edf3appTff7b72.Td2a8ff_build_reticulum_instance_settingsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/management-identitiesTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_management_identities_getTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787management_identities Tff7b72import Tb4b4b4(
Te6edf3list_management_identitiesTb4b4b4,
Tb4b4b4)

Te6edf3identities Tff7b72= Te6edf3list_management_identitiesTb4b4b4(
Tffa657getattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulum_config_dirTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4: Te6edf3identitiesTb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/management-identitiesTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_management_identities_postTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787management_identities Tff7b72import Tb4b4b4(
Te6edf3create_management_identityTb4b4b4,
Tb4b4b4)

Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid request bodyTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3name Tff7b72= Tb4b4b4(Te6edf3data Tff7b72or Tb4b4b4{Tb4b4b4}Tb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4)
Te6edf3force Tff7b72= Tffa657boolTb4b4b4(Tb4b4b4(Te6edf3data Tff7b72or Tb4b4b4{Tb4b4b4}Tb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffforceTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3identity Tff7b72= Te6edf3create_management_identityTb4b4b4(
Tffa657getattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulum_config_dirTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)Tb4b4b4,
Te6edf3name Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4,
Te6edf3forceTff7b72=Te6edf3forceTb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149FileExistsError Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff409Tb4b4b4)
Tff7b72except Tf85149ValueError Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff400Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffidentityTa5d6ff"Tb4b4b4: Te6edf3identityTb4b4b4}Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/reloadTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_reloadTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3success Tff7b72= Tff7b72await Te6edf3appTff7b72.Td2a8ffreload_reticulumTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3successTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffReticulum reloaded successfullyTa5d6ff"Tb4b4b4}Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffFailed to reload ReticulumTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff500Tb4b4b4,
Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/config/rawTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_config_raw_getTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e"""Return the raw text of the Reticulum config file.

Used by the Reticulum Config Editor utility (mostly for mobile
clients where the file is stored inside private app storage and
cannot easily be opened with an external editor).
"""
Tff7b72tryTb4b4b4:
Te6edf3appTff7b72.Td2a8ff_ensure_reticulum_configTb4b4b4(Te6edf3materializeTff7b72=Tff7b72FalseTb4b4b4)
Te6edf3config_path Tff7b72= Te6edf3appTff7b72.Td2a8ff_reticulum_config_file_pathTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffReticulum config not found at Tffd700{Te6edf3config_pathTffd700}Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff404Tb4b4b4,
Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3config_pathTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3content Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4: Te6edf3contentTb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3config_pathTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffputTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/config/rawTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_config_raw_putTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e"""Persist new raw text to the Reticulum config file.

The body must be JSON with a content string. Basic validation
requires the [reticulum] and [interfaces] sections so we
do not write a config that would prevent RNS from starting on the
next reload.
"""
Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffInvalid JSON bodyTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Te6edf3content Tff7b72= Te6edf3dataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3contentTb4b4b4, Tffa657strTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMissing or invalid Ta5d6ff'Ta5d6ffcontentTa5d6ff'Ta5d6ff fieldTa5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Tff7b72if Ta5d6ff"Ta5d6ff[reticulum]Ta5d6ff" Tff7b72not Tff7b72in Te6edf3content Tff7b72or Ta5d6ff"Ta5d6ff[interfaces]Ta5d6ff" Tff7b72not Tff7b72in Te6edf3contentTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffConfig must include [reticulum] and [interfaces] sectionsTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)

Tff7b72tryTb4b4b4:
Te6edf3config_dir Tff7b72= Te6edf3appTff7b72.Td2a8ff_normalize_reticulum_config_dirTb4b4b4(
Te6edf3appTff7b72.Td2a8ffreticulum_config_dirTb4b4b4,
Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3config_dirTb4b4b4)Tb4b4b4:
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3config_dirTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3config_path Tff7b72= Te6edf3appTff7b72.Td2a8ff_reticulum_config_file_pathTb4b4b4(Tb4b4b4)
Te6edf3previous_interfaces Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3config_pathTb4b4b4)Tb4b4b4:
Tff7b72tryTb4b4b4:
Tff7b72from T7ee787RNST7ee787.T7ee787vendorT7ee787.T7ee787configobj Tff7b72import Te6edf3ConfigObj

Te6edf3previous_interfaces Tff7b72= Te6edf3ConfigObjTb4b4b4(Te6edf3config_pathTb4b4b4)Tff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffinterfacesTa5d6ff"Tb4b4b4) Tff7b72or Tb4b4b4{Tb4b4b4}
Tff7b72except Tf85149ExceptionTb4b4b4:
Te6edf3previous_interfaces Tff7b72= Tb4b4b4{Tb4b4b4}
Te6edf3i2p_raw_error Tff7b72= Te6edf3i2p_supportTff7b72.Td2a8ffvalidate_raw_config_i2p_policyTb4b4b4(
Te6edf3contentTb4b4b4,
Te6edf3previous_interfacesTff7b72=Te6edf3previous_interfacesTb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3i2p_raw_error Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Te6edf3i2p_raw_errorTb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff422Tb4b4b4,
Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3config_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3contentTb4b4b4)
Te6edf3i2p_supportTff7b72.Td2a8ffguard_i2p_interfaces_in_configTb4b4b4(Te6edf3config_pathTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffReticulum config savedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3config_pathTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)

Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/reticulum/config/resetTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffreticulum_config_resetTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e"""Restore the Reticulum config file to RNS stock defaults."""
Tff7b72tryTb4b4b4:
Te6edf3appTff7b72.Td2a8ffreticulum_config_dir Tff7b72= Te6edf3appTff7b72.Td2a8ff_normalize_reticulum_config_dirTb4b4b4(
Te6edf3appTff7b72.Td2a8ffreticulum_config_dirTb4b4b4,
Tb4b4b4)
Te6edf3config_path Tff7b72= Te6edf3appTff7b72.Td2a8ff_reticulum_config_file_pathTb4b4b4(Tb4b4b4)
Te6edf3default_text Tff7b72= Te6edf3appTff7b72.Td2a8ff_write_rns_reticulum_default_config_fileTb4b4b4(
Te6edf3config_pathTb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffReticulum config restored to defaultsTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4: Te6edf3default_textTb4b4b4,
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3config_pathTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6fferrorTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tb4b4b4}Tb4b4b4, Te6edf3statusTff7b72=T79c0ff500Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────